﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;


//网格中的物质   一个 网格中 可以有多种物质   但是有相同的温度 其他属性算 平均值  渲染的时候去最多的三种显示
//一个 网格中的物质 可能是气态 液态和固态  并按照 从上往下的顺序存在
public class MatterGrid
{
    public event System.Action UpdateEvent;
    int _x, _y;
    public int X
    {
        get { return _x; }
    }
    public int Y
    {
        get { return _y; }
    }
    public MatterGrid(int x,int y )
    {
        _x = x;
        _y = y;
        for(int i = 0; i < _airBlock.Length;i++)
        {
            _airBlock[i] = 0.0f;
            _thisFrameAirBlock[i] = 0.0f;
            _lastFrameAirBlock[i] = 0.0f;
        }
        ShuiZhengQi = new Matter(){  currentMatterState = Matter.MatterState.Gas, matterType = MatterTypeConfig.AllMatters["水蒸汽"], Mass = 0.0f, Temperature = _temperature };
    }

    public float[] gasMovement = new float[4];                      //0为上 1为右 2 为下  3为左
    public float[] gasMovement2 = new float[4];                      //0为上 1为右 2 为下  3为左


    public List<Matter> Matters = new List<Matter>();                //所有物质
    public List<Matter> SolidMatter = new List<Matter>();           //按溶点排序的固体
    public List<Matter> SolidMatterByMassShowPriority = new List<Matter>();     //按照质量显示优先级 从大到小
    public List<Matter> liquidMatterByBoil = new List<Matter>();    //按沸腾点排序的液体
    public List<Matter> liquidMatterByMelt = new List<Matter>();     //按凝固点排序的液体
    public List<Matter> GasMatter = new List<Matter>();              //按液化点排+序的气体

    /// <summary>
    /// 空气中含的水蒸气,  其只有在过饱和状态下 会 变成水 瞬间
    /// 水 如果接触的空气 没有进入过饱和状态 会缓慢的变成 水蒸汽  
    /// 转换的速度和 相对湿度有关系 状态转换会产生正常的 能量变化
    /// 水蒸汽也会参与气压的计算
    /// </summary>
    public Matter ShuiZhengQi;                                      //
    public float PM25 = 0.0f;                                        //单位  ug/立方米 
    public float PM10 = 0.0f;                                        // 单位  ug/立方米

    public float lockedTemperature = 20.0f;    //被锁定了的温度  注意 物体的状态变化
    public bool LockTemperature = false;    //锁定了温度  在每次计算后会重置温度
    public bool CannotDig = false;          //这一格不能挖 

    public List<Matter> LockedAir;
    public bool LockAir = false;            //锁定空气内容


    float _temperature = 20.0f;                               //默认 20度的常温
    float _gasPressure = GlobalConst.StandardPressure;      //默认 一个大气压
    bool _dirty = false;

    float _lastUpdateTime;
    public void ResetTime()
    {
        _lastUpdateTime = Time.unscaledTime;
    }

    float[] _airBlock = new float[4];
    float[] _thisFrameAirBlock = new float[4];
    float[] _lastFrameAirBlock = new float[4];
    bool AirBlockActive = false;
    /// <summary>
    /// 设置这个格子 可能会被 AirBlock
    /// </summary>
    /// <param name="ison"></param>
    public void SetMaybeAirBlock(bool ison)
    {
        AirBlockActive = ison;
    }

    /// <summary>
    ///  在每一帧的开始调用 记录当前的值
    /// </summary>
    public void BeginAirBlock()
    {
        if(!AirBlockActive)
        {
            return;
        }
        _lastFrameAirBlock[0] = _airBlock[0];
        _lastFrameAirBlock[1] = _airBlock[1];
        _lastFrameAirBlock[2] = _airBlock[2];
        _lastFrameAirBlock[3] = _airBlock[3];

        _thisFrameAirBlock[0] = _airBlock[0];
        _thisFrameAirBlock[1] = _airBlock[1];
        _thisFrameAirBlock[2] = _airBlock[2];
        _thisFrameAirBlock[3] = _airBlock[3];



    }

    /// <summary>
    /// 在每一帧的结束调用  并与帧开始的时候 进行 比较 并处理具体逻辑
    /// </summary>
    public void EndAirBlock()
    {
        if(!AirBlockActive)
        {
            return;
        }
        if (_lastFrameAirBlock[0] == _thisFrameAirBlock[0] &&
           _lastFrameAirBlock[1] == _thisFrameAirBlock[1] &&
           _lastFrameAirBlock[2] == _thisFrameAirBlock[2] &&
           _lastFrameAirBlock[3] == _thisFrameAirBlock[3])
        {
            return;
        }
        //记录 block 前的4个方向的连同状态
        //如果block 之后  空间为0 则将气体平分到相同的格子
        //如果格子都不通 则 直接灭失掉       这是一个临时的方案 
        float beforeVolume = GetGasVolume();

        float afterVolume = GetGasVolumeWithTempBlock();
        if (afterVolume == 0.0f && beforeVolume > 0.0f)
        {
            #region 需要将 当前这个格子的气体 挤到附近的格子中
            float totalsurface = 0.0f;
            MatterGrid up = MainGame.Instance.Scene.GetGrid(X, Y + 1);
            float upSurface = 0.0f;
            if (up != null)
            {
                upSurface = MatterGrid.GetAirSurface(this, up);
            }

            MatterGrid down = MainGame.Instance.Scene.GetGrid(X, Y - 1);
            float downSurface = 0.0f;
            if (down != null)
            {
                downSurface = MatterGrid.GetAirSurface(this, down);
            }

            MatterGrid left = MainGame.Instance.Scene.GetGrid(X + 1, Y);
            float leftSurface = 0.0f;
            if (left != null)
            {
                leftSurface = MatterGrid.GetAirSurface(this, left);
            }

            MatterGrid right = MainGame.Instance.Scene.GetGrid(X - 1, Y);
            float rightSurface = 0.0f;
            if (left != null)
            {
                rightSurface = MatterGrid.GetAirSurface(this, right);
            }
            totalsurface = upSurface + downSurface + leftSurface + rightSurface;
            if (totalsurface == 0.0f)
            {

            }
            else
            {
                List<Matter> newgas = new List<Matter>();
                for (int i = 0; i < GasMatter.Count; i++)
                {
                    newgas.Add(GasMatter[i]);
                }
                for (int i = 0; i < GasMatter.Count; i++)
                {
                    Matters.Remove(GasMatter[i]);
                }
                GasMatter.Clear();

                if (up != null && upSurface != 0.0f)
                {
                    for (int k = 0; k < newgas.Count; k++)
                    {
                        var ng = newgas[k].Clone();
                        ng.Mass = newgas[k].Mass * upSurface / totalsurface;
                        up.AddMatter(ng);
                    }
                }
                if (down != null && downSurface != 0.0f)
                {
                    for (int k = 0; k < newgas.Count; k++)
                    {
                        var ng = newgas[k].Clone();
                        ng.Mass = newgas[k].Mass * downSurface / totalsurface;
                        down.AddMatter(ng);
                    }
                }
                if (left != null && leftSurface != 0.0f)
                {
                    for (int k = 0; k < newgas.Count; k++)
                    {
                        var ng = newgas[k].Clone();
                        ng.Mass = newgas[k].Mass * leftSurface / totalsurface;
                        left.AddMatter(ng);
                    }
                }
                if (right != null && rightSurface != 0.0f)
                {
                    for (int k = 0; k < newgas.Count; k++)
                    {
                        var ng = newgas[k].Clone();
                        ng.Mass = newgas[k].Mass * rightSurface / totalsurface;
                        right.AddMatter(ng);
                    }
                }
            }
            #endregion
        }
        _airBlock[0] = _thisFrameAirBlock[0];
        _airBlock[1] = _thisFrameAirBlock[1];
        _airBlock[2] = _thisFrameAirBlock[2];
        _airBlock[3] = _thisFrameAirBlock[3];
    }

    //设定空气是不是堵塞 //设为true 后 这个格子将不会允许有空气存在 0 到4 分别为 上右下左
    public void SetAirBlock(int direction,float value)
    {
        if(!AirBlockActive)
        {
            Debug.LogError("这个格子没有激活空气体积阻塞 设置失败");
        }
        _thisFrameAirBlock[direction] = value;
    }



    public float GetAndResetTime()
    {
        float currenttime = Time.unscaledTime;
        float templast = currenttime - _lastUpdateTime;
        _lastUpdateTime = currenttime;
        return templast;
    }
    /// <summary>
    /// 将 这个格子的物质 与物质M 的温度平均 , 期间可能会触发格子或者物质M 的状态变化
    /// </summary>
    /// <param name="m"></param>
    void AverageMatterTemperature(Matter m)
    {
        //按照比热 算出预期的 平均温度
        //然后 检查运行到这个温度 的时候 是否触发了 状态转换 触发到了的话 则
        float dt = m.Temperature - _temperature;
        float k1 = m.Mass * m.matterType.SpecificHeat;
        float k2 = TotalMass * AverageSpecificHeat;
        float energy = dt / ( k1 + k2);
        float tempt = energy * k1 + _temperature;   //能量平均之后的预期温度
                                                    //如果到这个温度会发生 状态变换 则将温度全部调整成状态转换之前的温度 
        if (dt > 0)
        {
            if (tempt > MinMeltingPointOrBoilingPoint || tempt < m.GetMaxTempStateChange()  )
            {
                //在平衡温度的时候发生状态改变 构建热力学折线方程 求解热量交换
                List<MyMathHelp.MultiSegmentFunction.Segment> a = BuildSegment(true);
                List<MyMathHelp.MultiSegmentFunction.Segment> b = m.BuildSegment(false);
                Vector2 v = MyMathHelp.MultiSegmentFunction.DoFunction(a, b); //v.x为改变的能量   v.y为终点温度 考虑到 可能发生溶解了一半的状态  分别将2个物体 修改能量
                bool inStateChange = EnergyChange(v.x);
                float oldtemp = m.Temperature; 
                Matter other = m.EnergyChange(-v.x, b);
                if ((other == null ? false :other.currentMatterState == Matter.MatterState.LiquidAndGas) || m.currentMatterState == Matter.MatterState.LiquidAndGas)
                {
                    Debug.LogError("物质状态错误");
                }

                if ((other == null ? false : other.currentMatterState == Matter.MatterState.SolidAndLiquid) || m.currentMatterState == Matter.MatterState.SolidAndLiquid)
                {
                    Debug.LogError("物质状态错误");
                }

                if(other != null)
                {
                    if (inStateChange)
                    {
                        if (other.Temperature != _temperature)
                        {
                            Debug.LogError("两者都处于状态转换中,温度应该绝对相等的");
                        }
                    }
                    else
                    {
                        //可能存在浮点数 误差 优先是有状态转换中对象的温度
                        _temperature = other.Temperature;
                        SetAllMatterTemperature(other.Temperature);
                    }
                    AddMatter(other);
                }
                else
                {
                    if ((m.Temperature - _temperature) > 0.001f)
                    {
                        Debug.LogError("计算出来的温度不对" + m.Temperature.ToString() + "    " + _temperature.ToString() + X.ToString() + "  " + Y.ToString());
                    }
                    m.Temperature = _temperature;   //强制相等 避免浮点数误差
                }
            }
            else
            {
                m.Temperature = tempt;
                _temperature = tempt;
                SetAllMatterTemperature(_temperature);
            }
        }
        if(dt < 0)
        {
            if (tempt < MaxMeltingPointOrBoilingPoint || tempt > m.GetMinTempStateChange())
            {
                //在平衡温度的时候发生状态改变 构建热力学折线方程 求解热量交换
                List<MyMathHelp.MultiSegmentFunction.Segment> a = BuildSegment(false);
                List<MyMathHelp.MultiSegmentFunction.Segment> b = m.BuildSegment(true);
                Vector2 v = MyMathHelp.MultiSegmentFunction.DoFunction(a, b); //v.x为改变的能量   v.y为终点温度 考虑到 可能发生溶解了一半的状态  分别将2个物体 修改能量
                bool inStateChange = EnergyChange(-v.x);
                Matter other = m.EnergyChange(v.x, b);
                if (other != null)
                {
                    if(inStateChange)
                    {
                        if (other.Temperature != _temperature )
                        {
                            Debug.LogError("计算出来的温度不对" + m.Temperature.ToString() + "    " + _temperature.ToString());
                        }
                    }
                    else
                    {
                        //可能存在浮点数 误差 优先是有状态转换中对象的温度
                        _temperature = other.Temperature;
                        SetAllMatterTemperature(other.Temperature);
                    }
                    AddMatter(other);
                }
                else
                {
                    if((m.Temperature - _temperature) > 0.001f)
                    {
                        Debug.LogError("计算出来的温度不对");
                    }
                    m.Temperature = _temperature;   //避免浮点数误差 
                }
            }
            else    //如果状态不会发生变化的 则直接 赋值温度
            {
                m.Temperature = tempt;
                _temperature = tempt;
                SetAllMatterTemperature(_temperature);
            }
        }
    }
        
    public void ClearMatter()
    {
        Matters.Clear() ;                //所有物质
        SolidMatter.Clear();           //按溶点排序的固体
        SolidMatterByMassShowPriority.Clear();     //按照质量显示优先级 从大到小
        liquidMatterByBoil.Clear();    //按沸腾点排序的液体
        liquidMatterByMelt.Clear();     //按凝固点排序的液体
        GasMatter.Clear();              //按液化点排+序的气体
    }

    public bool AddMatter(Matter m)
    {
        //先将温度做平 
        if(Matters.Count == 0)
        {
            _temperature = m.Temperature;
        }
        else
        {

            if (m.Temperature != _temperature)  //如果加入的物体 和 这个格子的温度不想等 则将能量进行平均 并将温度设为一个稳定的温度
            {
                AverageMatterTemperature(m);
            }
        }


        //判断重复加入  
        //因为温度已经平衡了  所以如果发现了相同类型的东西 则可以直接合并质量
        bool allreadyFound = false;
        for (int i = 0; i < Matters.Count;i++)
        {
            if(Matters[i].matterType == m.matterType && Matters[i].currentMatterState == m.currentMatterState)
            {
                Matters[i].Mass += m.Mass;
                allreadyFound = true;
                break;
            }
        }
        bool keep = false;  //这个对象是否还保留
        if(!allreadyFound)
        {
            keep = true;
            Matters.Add(m);
        }

        switch (m.currentMatterState)
        {
            case Matter.MatterState.Solid:
                if(allreadyFound)
                {

                }
                else
                {
                    SolidMatter.Add(m);
                    SolidMatterByMassShowPriority.Add(m);
                    SortByMeltingPointMinMax(SolidMatter);
                    SolidMatterByMassShowPriority.Sort((a, b) =>
                    {
                        return (int)(b.matterType.ShowPriority * b.Mass - a.matterType.ShowPriority * a.Mass);
                    }
                    );
                }

                break;
            case Matter.MatterState.Liquid:
                if(allreadyFound)
                {

                }
                else
                {
                    liquidMatterByBoil.Add(m);
                    liquidMatterByMelt.Add(m);
                    SortByBoilingPointMinMax(liquidMatterByBoil);
                    SortByMeltingPointMaxMin(liquidMatterByMelt);
                }
                break;
            case Matter.MatterState.Gas:
                if (allreadyFound)
                {

                }
                else
                {
                    GasMatter.Add(m);
                    SortByBoilingPointMaxMin(GasMatter);
                }
                break;
        }
        _dirty = true;
        return keep;
    }

    float _averageHeatTransferCoefficient;
    float _totalMass;
    float _totalGasMass;
    float _averageSpecificHeat;

    float _minMeltingPointOrBoilingPoint;  //最低的固体溶点或者液体沸点
    float _maxMeltingPointOrBoilingPoint;  //最高的气体液化点或者液体凝固点

    /// <summary>
    /// 
    /// </summary>
    /// <param name="dEnergy"> 需要改变的能量值  单位 KJ</param>
    /// <returns>为true 的话 说明当前的温度为 某个物体的 状态转换中(冰水混合物概念)</returns>

    public bool EnergyChange(float dEnergy)     //修改温度        //发生能量变化
    {
        float dtemperature = dEnergy / (AverageSpecificHeat * _totalMass);
        float tempT = _temperature + dtemperature;
        if(tempT < GlobalConst.AbsoluteZero)
        {
            Debug.Break();
        }
        if (dtemperature > 0)   //检测温度的变化是否触及到了某项的 溶点 或者沸点没有 如果有 则计算对应的溶化或者沸腾事件
        {
            if (tempT > MinMeltingPointOrBoilingPoint)  //触发到了融化事件或者 沸腾事件
            {
                float dtemp = MinMeltingPointOrBoilingPoint - _temperature;
                _temperature = MinMeltingPointOrBoilingPoint;  //先将温度将到 触发点
                SetAllMatterTemperature(_temperature);
                dEnergy -= dtemp * (AverageSpecificHeat * _totalMass); //吸收掉多余的能量
                //处理 溶化或者沸腾事件
                float leftEnergy = MeltOrBoiling(dEnergy);
                if (leftEnergy > 0)
                {
                    return EnergyChange(leftEnergy);
                }
                else
                {
                    return true;
                }
            }
            else
            {
                //没有触发到 溶化或者 汽化事件 直接提高温度
                _temperature = tempT;
                SetAllMatterTemperature(_temperature);
                return false;
            }
        }
        else if (dtemperature < 0)//检测温度的变化是否触及到了某项的 溶点 或者沸点没有 如果有 则计算对应的液化,凝固事件
        {
            //触发到了液化 或者凝固事件
            if (tempT < MaxMeltingPointOrBoilingPoint)  //触发到了液化 或者 凝固事件
            {
                float dtemp = MaxMeltingPointOrBoilingPoint - _temperature;
                _temperature = MaxMeltingPointOrBoilingPoint;  //先将温度将到 触发点
                SetAllMatterTemperature(_temperature);
                dEnergy -= dtemp * (AverageSpecificHeat * _totalMass); //吸收掉多余的能量
                //处理 溶化或者沸腾事件
                float leftEnergy = FreezOrLiquefaction(dEnergy);//这里为负数
                if (leftEnergy < 0)
                {
                    return EnergyChange(leftEnergy);
                }
                else
                {
                    return true;
                }

            }
            else
            {
                //没有触发到 凝固或者液化事件 直接设置温度
                _temperature = tempT;
                SetAllMatterTemperature(_temperature);
                return false;
            }
        }
        _dirty = true;
        return false;
    }

    public void SetAllMatterTemperature(float temperature)
    {
        if(temperature == -300.0f)
        {
            Debug.Break();
        }
        _temperature = temperature;
        for(int i = 0; i < SolidMatter.Count;i++)
        {
            SolidMatter[i].Temperature = temperature;
        }
        for (int i = 0; i < liquidMatterByBoil.Count; i++)
        {
            liquidMatterByBoil[i].Temperature = temperature;
        }
        for (int i = 0; i < GasMatter.Count; i++)
        {
            GasMatter[i].Temperature = temperature;
        }
    }



    float MeltOrBoiling(float dEnergy)    //溶化 或者 沸腾
    {
        if ((SolidMatter.Count == 0 ? GlobalConst.MaxTemperature : SolidMatter[0].matterType.MeltingPoint) < (liquidMatterByBoil.Count == 0 ? GlobalConst.MaxTemperature : liquidMatterByBoil[0].matterType.BoilingPoint))
        {
            #region 融化事件
            if (SolidMatter[0].matterType.HeatOfFusion * SolidMatter[0].Mass < dEnergy) //全部溶化成液体
            {
                float outvalue = dEnergy - SolidMatter[0].matterType.HeatOfFusion * SolidMatter[0].Mass;
                SolidMatter[0].currentMatterState = Matter.MatterState.Liquid;
                bool allreadyAdd = false;
                for (int i = 0; i < liquidMatterByBoil.Count; i++)
                {
                    if (liquidMatterByBoil[i].matterType == SolidMatter[0].matterType)
                    {
                        liquidMatterByBoil[i].Mass += SolidMatter[0].Mass;
                        allreadyAdd = true;
                        break;
                    }
                }

                Matters.Remove(SolidMatter[0]);
                SolidMatterByMassShowPriority.Remove(SolidMatter[0]);
                if (!allreadyAdd)
                {
                    AddMatter(SolidMatter[0]);
                }
                SolidMatter.RemoveAt(0);
                _dirty = true;
                return outvalue;
            }
            else
            {
                //能量 只够溶化部分固体
                float mass = dEnergy / SolidMatter[0].matterType.HeatOfFusion ;
                SolidMatter[0].Mass -= mass;
                //先检测 液体堆里是否有对应的同类物质 如果没有话 则
                bool allreadyAdd = false;
                for (int i = 0; i < liquidMatterByBoil.Count; i++)
                {
                    if (liquidMatterByBoil[i].matterType == SolidMatter[0].matterType)
                    {
                        liquidMatterByBoil[i].Mass += mass;
                        allreadyAdd = true;
                        break;
                    }
                }                
                if(!allreadyAdd)
                {
                    Matter newm = SolidMatter[0].Clone();
                    newm.currentMatterState = Matter.MatterState.Liquid;
                    newm.Mass = mass;
                    AddMatter(newm);
                    _dirty = true;
                }
                return 0.0f;
            }
            #endregion
        }
        else
        {
            #region 汽化事件
            if (liquidMatterByBoil[0].matterType.HeatOfGasification * liquidMatterByBoil[0].Mass < dEnergy) //全部气化
            {
                float outvalue = dEnergy - liquidMatterByBoil[0].matterType.HeatOfGasification * liquidMatterByBoil[0].Mass;
                liquidMatterByBoil[0].currentMatterState = Matter.MatterState.Gas;

                bool allreadyAdd = false;
                for (int i = 0; i < GasMatter.Count; i++)
                {
                    if (GasMatter[i].matterType == liquidMatterByBoil[0].matterType)
                    {
                        GasMatter[i].Mass += liquidMatterByBoil[0].Mass;
                        allreadyAdd = true;
                        break;
                    }
                }
                Matters.Remove(liquidMatterByBoil[0]);
                if (!allreadyAdd)
                {
                    AddMatter(liquidMatterByBoil[0]);
                }
                liquidMatterByMelt.Remove(liquidMatterByBoil[0]);
                liquidMatterByBoil.RemoveAt(0);
                _dirty = true;
                return outvalue;
            }
            else
            {
                //能量 只够溶化部分固体
                float mass = dEnergy / liquidMatterByBoil[0].matterType.HeatOfGasification;
                liquidMatterByBoil[0].Mass -= mass;
                //先检测 液体堆里是否有对应的同类物质 如果没有话 则
                bool allreadyAdd = false;
                for (int i = 0; i < GasMatter.Count; i++)
                {
                    if (GasMatter[i].matterType == liquidMatterByBoil[0].matterType)
                    {
                        GasMatter[i].Mass += mass;
                        allreadyAdd = true;
                        break;
                    }
                }
                if (!allreadyAdd)
                {
                    Matter newm = liquidMatterByBoil[0].Clone();
                    newm.currentMatterState = Matter.MatterState.Gas;
                    newm.Mass = mass;
                    AddMatter(newm);
                }
                return 0.0f;
            }
            #endregion
        }
    }

    float FreezOrLiquefaction(float dEnergy) //凝固或者 液化 dEnergy 为负数
    {
        float absdEnergy = Mathf.Abs(dEnergy);
        if ((GasMatter.Count == 0 ? GlobalConst.MinTemperature: GasMatter[0].matterType.BoilingPoint) > (liquidMatterByMelt.Count == 0 ? GlobalConst.MinTemperature: liquidMatterByMelt[0].matterType.MeltingPoint))
        {
            #region  液化
            if (GasMatter[0].matterType.HeatOfGasification * GasMatter[0].Mass < absdEnergy) //全部液化
            {
                float outvalue = absdEnergy - GasMatter[0].matterType.HeatOfGasification * GasMatter[0].Mass;
                GasMatter[0].currentMatterState = Matter.MatterState.Liquid;
                bool allreadyAdd = false;
                for (int i = 0; i <liquidMatterByBoil.Count;i++)
                {
                    if(liquidMatterByBoil[i].matterType == GasMatter[0].matterType)
                    {
                        liquidMatterByBoil[i].Mass += GasMatter[0].Mass;
                        allreadyAdd = true;
                        break;
                    }
                }
                Matters.Remove(GasMatter[0]);
                if (!allreadyAdd)
                {
                    AddMatter(GasMatter[0]);
                }
                GasMatter.RemoveAt(0);
                _dirty = true;
                return -outvalue;
            }
            else
            {
                //能量 只够溶化部分固体
                float mass = absdEnergy / GasMatter[0].matterType.HeatOfGasification;
                GasMatter[0].Mass -= mass;
                //先检测 液体堆里是否有对应的同类物质 如果没有话 则
                bool allreadyAdd = false;
                for (int i = 0; i < liquidMatterByBoil.Count; i++)
                {
                    if (liquidMatterByBoil[i].matterType == GasMatter[0].matterType)
                    {
                        liquidMatterByBoil[i].Mass += mass;
                        allreadyAdd = true;
                        break;
                    }
                }
                if (!allreadyAdd)
                {
                    Matter newm = GasMatter[0].Clone();
                    newm.currentMatterState = Matter.MatterState.Liquid;
                    newm.Mass = mass;
                    AddMatter(newm);
                }
                return 0.0f;
            }
            #endregion
        }
        else
        {
            #region  凝固
            if(liquidMatterByMelt.Count == 0)
            {
                Debug.Break();
            }
            if (liquidMatterByMelt[0].matterType.HeatOfFusion * liquidMatterByMelt[0].Mass < absdEnergy) //全部凝固
            {
                float outvalue = absdEnergy - liquidMatterByMelt[0].matterType.HeatOfFusion * liquidMatterByMelt[0].Mass;
                liquidMatterByMelt[0].currentMatterState = Matter.MatterState.Solid;
                bool allreadyadd = false;
                for (int i = 0; i < SolidMatter.Count;i++)
                {
                    if(SolidMatter[i].matterType == liquidMatterByMelt[0].matterType)
                    {
                        SolidMatter[i].Mass += liquidMatterByMelt[0].Mass;
                        allreadyadd = true;
                        break;
                    }
                }
                Matters.Remove(liquidMatterByMelt[0]);
                if (!allreadyadd)
                {
                    AddMatter(liquidMatterByMelt[0]);
                }
                liquidMatterByBoil.Remove(liquidMatterByMelt[0]);
                liquidMatterByMelt.RemoveAt(0);
                _dirty = true;
                return -outvalue;
            }
            else
            {
                //能量 凝固部分液体
                float mass = absdEnergy / liquidMatterByMelt[0].matterType.HeatOfFusion;
                liquidMatterByMelt[0].Mass -= mass;
                //先检测 液体堆里是否有对应的同类物质 如果没有话 则
                bool allreadyAdd = false;
                for (int i = 0; i < SolidMatter.Count; i++)
                {
                    if (liquidMatterByBoil[i].matterType == SolidMatter[0].matterType)
                    {
                        SolidMatter[i].Mass += mass;
                        allreadyAdd = true;
                        break;
                    }
                }
                if (!allreadyAdd)
                {
                    Matter newm = liquidMatterByMelt[0].Clone();
                    newm.currentMatterState = Matter.MatterState.Solid;
                    newm.Mass = mass;
                    AddMatter(newm);
                }
                return 0.0f;
            }
            #endregion
        }

    }


    //按照溶点 从低到高
    static void SortByMeltingPointMinMax(List<Matter> solidMatter)
    {
        solidMatter.Sort((a, b) =>
            {
                return (int)(a.matterType.MeltingPoint - b.matterType.MeltingPoint);
            }
        );
    }
    static void SortByMeltingPointMaxMin(List<Matter> solidMatter)
    {
        solidMatter.Sort((a, b) =>
        {
            return (int)(b.matterType.MeltingPoint - a.matterType.MeltingPoint);
        }
        );
    }

    //按照液化点 从低到高
    static void SortByBoilingPointMinMax(List<Matter> solidMatter)
    {
        solidMatter.Sort((a, b) =>
        {
            return (int)(a.matterType.BoilingPoint - b.matterType.BoilingPoint);
        }
        );
    }

    //按照液化点 从高到低
    static void SortByBoilingPointMaxMin(List<Matter> solidMatter)
    {
        solidMatter.Sort((a, b) =>
        {
            return (int)(b.matterType.BoilingPoint - a.matterType.BoilingPoint);
        }
        );
    }


    public void CalcDirty()
    {
        _totalMass = 0.0f;
        float totalHeatTransferCoefficient = 0.0f;
        float totalSpecificHeat = 0.0f;
        for (int i = 0; i < Matters.Count; i++)
        {
            var m = Matters[i];
            totalHeatTransferCoefficient += m.matterType.HeatTransferCoefficient * m.Mass;
            totalSpecificHeat += m.matterType.SpecificHeat * m.Mass;
            _totalMass += m.Mass;
        }
        _totalGasMass = 0.0f;
        for (int i = 0; i < GasMatter.Count;i++ )
        {
            _totalGasMass += GasMatter[i].Mass;
        }
        _averageHeatTransferCoefficient = totalHeatTransferCoefficient / _totalMass;
        _averageSpecificHeat = totalSpecificHeat / _totalMass;
        _minMeltingPointOrBoilingPoint = Mathf.Min(SolidMatter.Count  == 0 ? GlobalConst.MaxTemperature : SolidMatter[0].matterType.MeltingPoint , liquidMatterByBoil.Count == 0 ? GlobalConst.MaxTemperature : liquidMatterByBoil[0].matterType.BoilingPoint);
        _maxMeltingPointOrBoilingPoint = Mathf.Max(liquidMatterByMelt.Count == 0  ? -300.0f: liquidMatterByMelt[0].matterType.MeltingPoint, GasMatter.Count == 0 ? - 300.0f: GasMatter[0].matterType.BoilingPoint);
        _gasPressure = GetGasPressure();
        _dirty = false;
    }


    public void Update(float dtime)    //计算一格之内的变化
    {

    }

    public void BroadCastUpdateEvent()
    {
        if (UpdateEvent != null)
        {
            UpdateEvent();
        }
    }

    public float AverageHeatTransferCoefficient
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _averageHeatTransferCoefficient;
        }
    }

    public float Temperature
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            if(_temperature == -300.0f)
            {
                Debug.Break();
            }
            return _temperature;
        }    
    }

    public float AverageSpecificHeat
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _averageSpecificHeat;
        }
    }

    public float TotalMass
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _totalMass;
        }
    }

    public float TotalGasMass
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _totalGasMass;
        }
    }

    public float GasPressure
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _gasPressure;
        }
    }

    public float MinMeltingPointOrBoilingPoint
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _minMeltingPointOrBoilingPoint;
        }
    }
    public float MaxMeltingPointOrBoilingPoint
    {
        get
        {
            if (_dirty)
            {
                CalcDirty();
            }
            return _maxMeltingPointOrBoilingPoint;
        }
    }


    /// <summary>
    /// 按照一定的百分比 抽出气体 用来做布朗运动
    /// </summary>
    /// <param name="percent"></param>
    /// <param name="dir"> 只能为1 0 -1 1代表其他向上流动 密度比平均密度低的气体或得到额外的气体奖励 最多2倍</param>
    /// <param name = "outvalues"> 为了防止内存分配需要传入 容器 </param>
    /// <returns></returns>
    public List<Matter> RemoveGasMatter(float percent,int dir,ref List<Matter> outvalues)
    {
        List<Matter> ms = outvalues;
        float gasp = GetGasPressure();
        float averageGasD = TotalGasMass / GetGasVolume();
        for (int i = 0; i < GasMatter.Count;i++)
        {
            float currentGasD = GlobalConst.GetGasDensity(GasMatter[i].matterType.AtomicWeight, Temperature, gasp);
            float dD =  currentGasD / averageGasD - 1.0f;
            if(Mathf.Abs(dD) < 0.2f)
            {
                dD = 0.0f;
            }
            if(dD> 1.0f)
            {
                dD = 1.0f;
            }
            float toRemoveMass = GasMatter[i].Mass * percent * (1.0f - dD * dir * GlobalConst.BrownianMovementByDensity);
            if(float.IsNaN(toRemoveMass))
            {
                Debug.LogError("Mass isNan "  + X.ToString() + "  " +  Y.ToString());
            }
            if(toRemoveMass > 0.0001f)
            {
                Matter m = Matter.Creat();
                m.Mass = toRemoveMass;
                GasMatter[i].Mass -= toRemoveMass;
                m.Temperature = Temperature;
                m.matterType = GasMatter[i].matterType;
                m.currentMatterState = GasMatter[i].currentMatterState;
                ms.Add(m);
            }
        }
        _dirty = true;
        return ms;
        //根据当前气体的密度 进行 百分比修正 修正的值非常少 
    }

    public float RemoveGasMatter(string name,float mass)
    {
        for(int i = 0; i < GasMatter.Count;i++)
        {
            if(GasMatter[i].matterType.Name == name)
            {
                if(GasMatter[i].Mass> mass)
                {
                    GasMatter[i].Mass = GasMatter[i].Mass - mass;
                    _dirty = true;
                    return 0.0f;
                }
                else
                {
                    mass = mass - GasMatter[i].Mass;
                    GasMatter[i].Mass = 0;
                    Matters.Remove(GasMatter[i]);
                    GasMatter.RemoveAt(i);
                    _dirty = true;
                    return mass;
                }
            }
        }
        return mass;
    }


    /// <summary>
    /// 按一定的比例移除液体 ,TODO:  优先移除  密度大的液体
    /// </summary>
    /// <param name="perceng"></param>
    /// <param name="outvalues"></param>
    /// <returns></returns>
    public List<Matter> RemoveLiquidMatter(float volume,ref List<Matter> outvalues)
    {
        
        List<Matter> ms = outvalues;
        for (int i = 0; i < liquidMatterByBoil.Count;i++ )
        {
            float currentv = liquidMatterByBoil[i].GetVolume();
            if(currentv >= volume)
            {
                Matter m = Matter.Creat();
                float toRemoveMass = volume * liquidMatterByBoil[i].matterType.DensityWhenLiquid;
                m.Mass = toRemoveMass;
                liquidMatterByBoil[i].Mass -= toRemoveMass;
                m.Temperature = Temperature;
                m.matterType = liquidMatterByBoil[i].matterType;
                m.currentMatterState = liquidMatterByBoil[i].currentMatterState;
                ms.Add(m);
                break;
            }
            else
            {
                ms.Add(liquidMatterByBoil[i]);
                volume -= currentv;
                Matter m = liquidMatterByBoil[i];
                liquidMatterByMelt.Remove(m);
                Matters.Remove(m);
                liquidMatterByBoil.Remove(m);
                i--;
            }
        }
        return ms;
    }
    
    struct StateChangeEnergy
    {
        public float Temperature;
        public float Energy;
    }
    public List<MyMathHelp.MultiSegmentFunction.Segment> BuildSegment(bool add)
    {
        if (add)
        {
            List<StateChangeEnergy> stateChanges = new List<StateChangeEnergy>();
            //如果是温度升高的话 
            for (int i = 0; i < SolidMatter.Count; i++)
            {
                StateChangeEnergy sce = new StateChangeEnergy() { Temperature = SolidMatter[i].matterType.MeltingPoint, Energy = SolidMatter[i].matterType.HeatOfFusion * SolidMatter[i].Mass };
                stateChanges.Add(sce);
                sce = new StateChangeEnergy() { Temperature = SolidMatter[i].matterType.BoilingPoint, Energy = SolidMatter[i].matterType.HeatOfGasification * SolidMatter[i].Mass };
                stateChanges.Add(sce);
            }
            for (int i = 0; i < liquidMatterByBoil.Count; i++)
            {
                StateChangeEnergy sce = new StateChangeEnergy() { Temperature = liquidMatterByBoil[i].matterType.BoilingPoint, Energy = liquidMatterByBoil[i].matterType.HeatOfGasification * liquidMatterByBoil[i].Mass };
                stateChanges.Add(sce);
            }
            stateChanges.Sort((a, b) =>
                {
                    return (int)((a.Temperature - b.Temperature) * 10000.0f);
                }
            );
            List<MyMathHelp.MultiSegmentFunction.Segment> outvalues = new List<MyMathHelp.MultiSegmentFunction.Segment>();
            float currentE = 0.0f;
            if (stateChanges.Count == 0)
            {
                //再来个10万度的 保证相交
                MyMathHelp.MultiSegmentFunction.Segment segmentEnd = new MyMathHelp.MultiSegmentFunction.Segment()
                {
                    StartPoint = new Vector2(currentE, _temperature),
                    EndPoint = new Vector2(currentE + (GlobalConst.MaxTemperature - _temperature) * TotalMass * AverageSpecificHeat, GlobalConst.MaxTemperature)
                };
                outvalues.Add(segmentEnd);
            }
            else
            {
                if (Temperature == stateChanges[0].Temperature)
                {
                    MyMathHelp.MultiSegmentFunction.Segment segment = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(0.0f, Temperature),
                        EndPoint = new Vector2(stateChanges[0].Energy, Temperature)
                    };
                    outvalues.Add(segment);
                    currentE += stateChanges[0].Energy;
                }
                for (int i = (Temperature == stateChanges[0].Temperature ? 1 : 0); i < stateChanges.Count; i++)
                {
                    float echange = (stateChanges[i].Temperature - (i == 0 ? Temperature : stateChanges[i - 1].Temperature)) * TotalMass * AverageSpecificHeat;
                    MyMathHelp.MultiSegmentFunction.Segment segment = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(currentE, i == 0 ? Temperature : stateChanges[i - 1].Temperature),
                        EndPoint = new Vector2(currentE + echange, stateChanges[i].Temperature)
                    };
                    currentE += echange;
                    outvalues.Add(segment);
                    MyMathHelp.MultiSegmentFunction.Segment segment1 = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(currentE, stateChanges[i].Temperature),
                        EndPoint = new Vector2(currentE + stateChanges[i].Energy, stateChanges[i].Temperature)
                    };
                    currentE += stateChanges[i].Energy;
                    outvalues.Add(segment1);
                }
                //再来个10万度的 保证相交
                MyMathHelp.MultiSegmentFunction.Segment segmentEnd = new MyMathHelp.MultiSegmentFunction.Segment()
                {
                    StartPoint = new Vector2(currentE, stateChanges[stateChanges.Count - 1].Temperature),
                    EndPoint = new Vector2(currentE + (GlobalConst.MaxTemperature - stateChanges[stateChanges.Count - 1].Temperature) * TotalMass * AverageSpecificHeat, GlobalConst.MaxTemperature)
                };
                outvalues.Add(segmentEnd);
            }
            return outvalues;
        }
        else
        {
            List<StateChangeEnergy> stateChanges = new List<StateChangeEnergy>();
            //如果是温度降低的话 
            for (int i = 0; i < GasMatter.Count; i++)
            {
                StateChangeEnergy sce = new StateChangeEnergy() { Temperature = GasMatter[i].matterType.BoilingPoint, Energy = GasMatter[i].matterType.HeatOfGasification * GasMatter[i].Mass };
                stateChanges.Add(sce);
                sce = new StateChangeEnergy() { Temperature = GasMatter[i].matterType.MeltingPoint, Energy = GasMatter[i].matterType.HeatOfFusion * GasMatter[i].Mass };
                stateChanges.Add(sce);
            }
            for (int i = 0; i < liquidMatterByBoil.Count; i++)
            {
                StateChangeEnergy sce = new StateChangeEnergy() { Temperature = liquidMatterByBoil[i].matterType.MeltingPoint, Energy = liquidMatterByBoil[i].matterType.HeatOfFusion * liquidMatterByBoil[i].Mass };
                stateChanges.Add(sce);
            }
            stateChanges.Sort((a, b) =>
            {
                return (int)((b.Temperature - a.Temperature) * 10000.0f);
            }
            );
            List<MyMathHelp.MultiSegmentFunction.Segment> outvalues = new List<MyMathHelp.MultiSegmentFunction.Segment>();
            float currentE = 0.0f;
            if (stateChanges.Count == 0)
            {
                //再来个-300度的 保证相交
                MyMathHelp.MultiSegmentFunction.Segment segmentEnd = new MyMathHelp.MultiSegmentFunction.Segment()
                {
                    StartPoint = new Vector2(currentE, _temperature),
                    EndPoint = new Vector2(currentE + (_temperature - (-300.0f)) * TotalMass * AverageSpecificHeat, -300.0f)
                };
                outvalues.Add(segmentEnd);

            }
            else
            {
                if (Temperature == stateChanges[0].Temperature)
                {
                    MyMathHelp.MultiSegmentFunction.Segment segment = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(0.0f, Temperature),
                        EndPoint = new Vector2(stateChanges[0].Energy, Temperature)
                    };
                    outvalues.Add(segment);
                    currentE += stateChanges[0].Energy;
                }
                for (int i = (Temperature == stateChanges[0].Temperature ? 1 : 0); i < stateChanges.Count; i++)
                {
                    float echange = ((i == 0 ? Temperature : stateChanges[i - 1].Temperature) - stateChanges[i].Temperature) * TotalMass * AverageSpecificHeat;
                    MyMathHelp.MultiSegmentFunction.Segment segment = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(currentE, i == 0 ? Temperature : stateChanges[i - 1].Temperature),
                        EndPoint = new Vector2(currentE + echange, stateChanges[i].Temperature)
                    };
                    currentE += echange;
                    outvalues.Add(segment);
                    MyMathHelp.MultiSegmentFunction.Segment segment1 = new MyMathHelp.MultiSegmentFunction.Segment()
                    {
                        StartPoint = new Vector2(currentE, stateChanges[i].Temperature),
                        EndPoint = new Vector2(currentE + stateChanges[i].Energy, stateChanges[i].Temperature)
                    };
                    currentE += stateChanges[i].Energy;
                    outvalues.Add(segment1);
                }
                //再来个-300度的 保证相交
                MyMathHelp.MultiSegmentFunction.Segment segmentEnd = new MyMathHelp.MultiSegmentFunction.Segment()
                {
                    StartPoint = new Vector2(currentE, stateChanges[stateChanges.Count - 1].Temperature),
                    EndPoint = new Vector2(currentE + (stateChanges[stateChanges.Count - 1].Temperature - (-300.0f)) * TotalMass * AverageSpecificHeat, -300.0f)
                };
                outvalues.Add(segmentEnd);
            }


            return outvalues;
        }
    }
    public float GetTotalEnergy()
    {
        float te = 0.0f;
        for(int i = 0; i < Matters.Count;i++)
        {
            te += Matters[i].GetTotalEnergy();
        }
        return te;
    }

    public float GetSolidVolume()
    {
        float outvalue = 0.0f;
        for(int i = 0; i < SolidMatter.Count;i++)
        {
            outvalue += SolidMatter[i].GetVolume();
        }
        return outvalue;
    }

    public float GetLiquidVolume()
    {
        float outvalue = 0.0f;

        for (int i = 0; i < liquidMatterByBoil.Count; i++)
        {
            outvalue += liquidMatterByBoil[i].GetVolume();
        }
        return outvalue;

    }

    public float GetTotalVolume()
    {
        float outvalue = 0.0f;
        for (int i = 0; i < Matters.Count; i++)
        {
            outvalue += Matters[i].GetVolume();
        }
        return outvalue;

    }
    /// <summary>
    /// 返回当前格子的 气体体积  该体积 刨除掉了  block 的部分
    /// </summary>
    /// <returns></returns>
    public float GetGasVolume()
    {
        float gasvolume = 1.0f - GetSolidVolume() - GetLiquidVolume();
        if (gasvolume <= 0.0f)
        {
            return 0.0f;
        }
        return Mathf.Max(0.0f, (Mathf.Min(gasvolume, 1.0f - _airBlock[2]) - _airBlock[0]) * (1.0f - (_airBlock[1] + _airBlock[3]))); 
    }

    /// <summary>
    /// 返回当前格子的气体体积 改体积包含了 临时 block 的部分 改函数在 airblock 中使用
    /// </summary>
    /// <returns></returns>
    float GetGasVolumeWithTempBlock()
    {
        float gasvolume = 1.0f - GetSolidVolume() - GetLiquidVolume();
        if (gasvolume <= 0.0f)
        {
            return 0.0f;
        }
        return Mathf.Max(0.0f, (Mathf.Min(gasvolume, 1.0f - _thisFrameAirBlock[2]) - _thisFrameAirBlock[0]) * (1.0f - (_thisFrameAirBlock[1] + _thisFrameAirBlock[3])));
    }

    /// <summary>
    ///  返回当前气体的体积 改体积没有被 airblock所刨除
    /// </summary>
    /// <returns></returns>
    public float GetGasVolumeWithoutBlock()
    {
        float gasvolume = 1.0f - GetSolidVolume() - GetLiquidVolume();
        if (gasvolume <= 0.0f)
        {
            return 0.0f;
        }
        return gasvolume;
    }
    //计算气压
    public float GetGasPressure()
    {
        float gasvolume = GetGasVolume();
        if(gasvolume <= 0.0f)
        {
            return 0.0f;
        }
        float gasPressure = 0.0f;
        for(int i = 0;i < GasMatter.Count;i++)
        {
            gasPressure += GasMatter[i].GetGasPressure(gasvolume, _temperature);
        }
        gasPressure += ShuiZhengQi.GetGasPressure(gasvolume, _temperature);
        if(float.IsNaN(gasPressure))
        {
            Debug.LogError("gasPressure is non");
        }
        return gasPressure;
    }

    public float GetMatterTypeMass(string typename)
    {
        float totalmass = 0.0f;
        for(int i = 0 ; i < Matters.Count;i++)
        {
            if(Matters[i].matterType.Name == typename)
            {
                totalmass += Matters[i].Mass;
            }
        }
        return totalmass;
    }
    /// <summary>
    /// 返回两个格子之间的 想通的气体关系 为0 则表示不相同
    /// </summary>
    public static float GetAirSurface(MatterGrid a,MatterGrid b)
    {
        //调用到这里的必然是合法的相邻关系
        //首先 判断  A 和 B 气体是否是想通的 再判断A和B 的上下关系
        if (a.Y != b.Y) //如果上下级 关系的话
        {
            MatterGrid Up = a.Y > b.Y ? a : b;
            MatterGrid Down = a.Y < b.Y ? a : b;
            if (Up.SolidMatter.Count != 0)
            {
                return 0.0f;
            }
            if (Up._airBlock[2] > 0.0f || Down._airBlock[0] > 0.0f)
            {
                return 0.0f;
            }            
            return Mathf.Max(0.0f, 1.0f - Mathf.Max(Up._airBlock[1], Down._airBlock[1]) - Mathf.Max(Up._airBlock[3], Down._airBlock[3]));
        }
        MatterGrid left = a.X < b.X ? a : b;
        MatterGrid right = a.X > b.X ? a : b;
        if (left._airBlock[1] > 0.0f || right._airBlock[3] > 0.0f)
        {
            return 0.0f;
        }
        return Mathf.Max(0.0f, 1.0f - Mathf.Max(left._airBlock[0], right._airBlock[0]) - Mathf.Max(left.GetGasVolumeWithoutBlock(),right.GetGasVolumeWithoutBlock(), left._airBlock[2], left._airBlock[2]));
    }
}
